package com.cqhfan.chatroom.service.impl;

import cn.hutool.core.util.StrUtil;
import com.cqhfan.chatroom.domain.vo.UserLoginVO;
import com.cqhfan.chatroom.service.ITokenService;
import com.cqhfan.common.autoconfigure.mvc.properties.SecurityProperties;
import com.cqhfan.common.constants.BizConstants;
import com.cqhfan.common.constants.RedisConstants;
import com.cqhfan.common.exceptions.UnLoginException;
import com.cqhfan.common.utils.JwtUtil;
import com.cqhfan.common.utils.MD5Util;
import io.jsonwebtoken.Claims;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author 眭传洪
 * @create 2024-11-14 20:26
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TokenServiceImpl implements ITokenService {

    private final StringRedisTemplate stringRedisTemplate;

    private final SecurityProperties securityProperties;

    @Override
    public String createAccessToken(Map<String, Object> map) {
        return JwtUtil.createToken(map, securityProperties.getPrivateKey(), securityProperties.getAccessTokenTtl());
    }

    @Override
    public String createRefreshToken(Map<String, Object> map) {
        // 生成refreshToken
        Long refreshTokenTtl = securityProperties.getRefreshTokenTtl();
        String refreshToken = JwtUtil.createToken(map, securityProperties.getPrivateKey(), refreshTokenTtl);

        // 将refreshToken保存到redis
        String refreshTokenKey = getRefreshTokenKey(refreshToken);
        stringRedisTemplate.opsForValue().set(refreshTokenKey, refreshToken, refreshTokenTtl, TimeUnit.MINUTES);

        return refreshToken;
    }

    @Override
    public UserLoginVO refreshToken(String refreshToken) {
        if (StrUtil.isBlank(refreshToken)) {
            throw new UnLoginException();
        }

        // 解析校验token信息
        Claims claims = JwtUtil.parseToken(refreshToken, securityProperties.getPublicKey());
        if (claims == null) {
            throw new UnLoginException();
        }

        // 校验是否是redis存的refreshToken
        String refreshTokenKey = getRefreshTokenKey(refreshToken);
        String cacheRefreshToken = stringRedisTemplate.opsForValue().get(refreshTokenKey);
        if (StrUtil.isBlank(cacheRefreshToken)) {
            throw new UnLoginException();
        }

        // 干掉旧的token
        stringRedisTemplate.delete(refreshTokenKey);

        // 重新构造返回
        Long userId = claims.get(BizConstants.TOKEN_USER_INFO, Long.class);
        Map<String, Object> map = new HashMap<>();
        map.put(BizConstants.TOKEN_USER_INFO, userId);
        return UserLoginVO.builder()
                .accessToken(createAccessToken(map))
                .refreshToken(createRefreshToken(map))
                .build();
    }

    private String getRefreshTokenKey(String refreshToken) {
        return RedisConstants.REFRESH_TOKEN_KEY_PREFIX + MD5Util.encrypt(refreshToken);
    }

    @Override
    public void deleteToken(String refreshToken) {
        String key = getRefreshTokenKey(refreshToken);
        stringRedisTemplate.delete(key);
    }
}
